Skip to content

S04-03 Web-网络请求

[TOC]

前后端分离

服务器端渲染

服务器端渲染(SSR,Server Side Render):是指在服务器上将 JS 应用(通常是 React, Vue, Angular, Svelte 等构建的)转换并生成完整的 HTML 页面,然后将这个可以直接渲染的 HTML 发送给浏览器(客户端)的过程。

早期的网页都是通过后端渲染来完成的:

  • 客户端发出请求 -> 服务端接收请求并返回相应HTML文档 -> 页面刷新,客户端加载新的HTML文档;

服务器端渲染的缺点

  • 会更新整个页面:当用户点击页面中的某个按钮向服务器发送请求时,页面本质上只是一些数据发生了变化,而此时服务器却要将重绘的整个页面再返回给浏览器加载,这显然有悖于程序员的“DRY( Don‘t repeat yourself )”原则;

  • 网络开销大:而且明明只是一些数据的变化却迫使服务器要返回整个HTML文档,这本身也会给网络带宽带来不必要的开销。

有没有办法在页面数据变动时,只向服务器请求新的数据,并且在阻止页面刷新的情况下,动态的替换页面中展示的数据呢?

  • 答案正是“AJAX”。

网页的渲染过程

服务器端渲染

image-20250818224921980

前后端分离

image-20250818224952398

HTTP

概念

HTTP

HTTP(HyperText Transfer Protocol,超文本传输协议):是互联网上应用最广泛的基础通信协议,用于在客户端(如浏览器)和服务器之间传输超文本(如网页、图片、视频等)。它是万维网(WWW)数据交换的基石,定义了数据如何打包、传输和解析。

  • 维基百科

    • HTTP 是一种用于分布式、协作式和超媒体信息系统的应用层协议;

    • HTTP是万维网的数据通信的基础,设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法;

    • 通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识;


HTTP是一个客户端(用户)和服务端(网站)之间请求和响应的标准。

  • 通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80),我们称这个客户端为用户代理程序(User Agent)

  • 响应的服务器上存储着一些资源,比如HTML文件和图像,我们称这个响应服务器为源服务器(Origin Server)

image-20230620152738414


核心特性

  1. 无状态(Stateless)

    每次请求独立,服务器不记录客户端状态。需 Cookie/Session 维持登录状态。

  2. 统一通信标准

    不同设备/系统间通过标准协议交换数据。

HTTPS

HTTPS(HyperText Transfer Protocol Secure是 HTTP 的安全版本,它在 HTTP 协议基础上增加了 TLS/SSL 加密层,用于保护客户端与服务器之间的数据传输。


HTTPS 的核心作用

  1. 数据加密:通过 TLS/SSL 加密传输内容,防止中间人攻击(如窃听、篡改)。
  2. 身份验证:通过数字证书验证服务器身份,避免连接伪造的服务器。
  3. 数据完整性:防止传输过程中数据被恶意修改。

HTTPS 在 JS 中的关键机制

  1. TLS/SSL 握手:客户端与服务器协商加密算法、交换密钥(JS 中由环境自动完成)。
  2. 证书验证:浏览器/Node.js 检查证书是否由受信任机构签发,域名是否匹配。
  3. 混合内容阻塞浏览器会阻止 HTTPS 页面中加载 HTTP 资源(如脚本、图片)。
  4. HSTS:强制浏览器只通过 HTTPS 访问网站(响应头 Strict-Transport-Security)。

URI

URI(Uniform Resource Identifiers,统一资源标识符):是一个用于唯一标识网络资源的字符串,它是 URL(统一资源定位符)和 URN(统一资源名称)的超集。


对比 URI/URL/URN

在 Web 开发中,URL 是最常用的 URI 子集

类型说明示例
URI标识资源的通用字符串https://example.com/产品?id=123#详情
URL定位资源的 URI(含协议和路径)https://example.com/page.html
URN命名资源的 URI(不依赖位置)urn:isbn:0451450523(书籍永久标识)

网页中的资源

我们网页中的资源通常是被放在 Web 资源服务器中,由浏览器自动发送 HTTP 请求来获取、解析、展示的。

目前我们页面中很多数据是动态展示的:

  • 比如页面中的数据展示、搜索数据、表单验证等等,也是通过在 JS 中发送 HTTP 请求获取的;

image-20250818160135649

image-20250818160158460

HTTP 组成

一次 HTTP 请求主要包括:请求(Request)和响应(Response)

image-20250818160527799

HTTP 请求

image-20250818160752108

HTTP 响应

image-20250818161148712

HTTP 版本

HTTP 的版本演进始终围绕 性能、安全与功能扩展 三大核心目标:

  1. HTTP/0.9发布:1991

    • 核心改进

      • 仅支持 GET 请求
      • 仅支持获取文本数据
    • 问题解决:基础原型

    • 说明:主要是为了获取 HTML 页面内容

  2. HTTP/1.0发布:1996

    • 核心改进
      • 引入 HEAD/POST 方法、状态码、请求头、响应头
      • 支持获取更多数据类型(不再局限于文本数据)
    • 问题解决:功能扩展
    • 说明
      • TCP短连接:浏览器的每次请求都需要与服务器建立一个TCP连接,请求处理完成后立即断开TCP连接,每次建立连接增加了性能损耗。
  3. HTTP/1.1发布:1999

    • 核心改进:持久连接、管道化、Host 头、分块传输
    • 问题解决:性能优化(主流版本
  4. HTTP/2.0发布:2015

    • 核心改进:二进制分帧、多路复用、头部压缩、服务器推送
    • 问题解决:解决队头阻塞、提升速度
  5. HTTP/3.0发布:2022

    • 核心改进:基于 QUIC 协议(UDP)、0-RTT 握手
    • 问题解决:减少延迟、优化弱网环境

HTTP 请求方式

RFC 7231中定义了一组请求方式,用于定义客户端希望服务器执行的操作类型

  • GET:获取资源。

  • POST:创建新资源。

  • PUT:完整替换资源。

  • DELETE:删除资源。

  • PATCH:部分更新资源。

  • CONNECT:建立一个到目标资源标识的服务器的隧道,通常用在代理服务器,网页开发很少用到。

  • TRACE:沿着到目标资源的路径执行一个消息环回测试

  • OPTIONS:获取服务器支持的通信选项。用于预检请求(CORS)。

  • HEAD:获取资源元数据。请求一个与 GET 请求的响应相同的响应,但没有响应体

    • 比如在准备下载一个文件前,先获取文件的大小,再决定是否进行下载;

HTTP 请求头

HTTP 请求头(HTTP Request Headers):是客户端(如浏览器)向服务器发送请求时传递的元数据,它们为服务器提供请求的上下文信息、客户端偏好、认证凭证等。


核心特性

  1. 大小限制:总请求头大小通常限制在 8-16KB

  2. 敏感信息:避免在请求头中传递敏感数据

  3. CORS:自定义头需要服务器设置 Access-Control-Allow-Headers

    js
    Access-Control-Allow-Headers: Content-Type, Authorization, X-Custom-Header
自定义请求头

自定义请求头的命名规范

  • 使用 X- 前缀(传统做法,非强制)
  • 语义化命名(如 X-Client-Version
  • 避免使用保留名称
  • CORS:自定义头需要服务器设置 Access-Control-Allow-Headers
js
headers: {
  'X-Client-ID': 'web-app-v1.2',
  'X-Request-Source': 'mobile'
}
常见请求头

常见 HTTP 请求头

类别请求头示例作用
内容协商Accept, Accept-Language, Accept-Encoding指定客户端可接受的内容类型
身份认证Authorization, Cookie传递用户凭证
缓存控制Cache-Control, If-Modified-Since控制缓存行为
客户端信息User-Agent, Referer提供客户端环境信息
请求体信息Content-Type, Content-Length描述请求体格式和大小
跨域请求Origin标识请求来源

image-20230620152904995


Content-Type

Content-Type:定义了请求体的数据格式,使服务器能够正确解析客户端发送的数据。

  • application/json最常用,发送 JSON 格式数据

    • 特点

      • 结构化数据,支持复杂对象
      • 现代 API 首选格式
      js
      fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: 'Alice', age: 28 })
      });
  • application/x-www-form-urlencoded:传统表单提交

    • 特点

      • 键值对格式:key1=value1&key2=value2
      • URL 编码特殊字符
      js
      const data = new URLSearchParams();
      data.append('username', 'john_doe');
      data.append('password', 'secure123');
      
      fetch('/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: data
      });
  • multipart/form-data:文件上传和表单混合提交

    • 特点

      • 支持二进制数据
      • 每个字段有独立内容类型
      • 需要 boundary 分隔符
      • 注意:文件上传时不设置Content-Type,让浏览器自动处理可以包含必要的 boundary 信息
      js
      const form = new FormData();
      form.append('name', 'John');
      form.append('avatar', fileInput.files[0]);
      
      fetch('/profile', {
        method: 'POST',
        body: form
        // 浏览器自动设置:
        // Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
      });
  • text/plain:发送纯文本内容

    • 特点

      • 无特殊格式处理
      • 适用于简单文本数据
      js
      fetch('/api/log', {
        method: 'POST',
        headers: { 'Content-Type': 'text/plain' },
        body: 'Error: Invalid user input at 2023-08-10T14:30:00Z'
      });
  • application/xml:发送 XML 格式数据

    • 特点

      • 传统企业系统常用
      • 比 JSON 更冗长
      js
      const xmlData = `
        <user>
          <name>John</name>
          <age>30</age>
        </user>
      `;
      
      fetch('/legacy-api', {
        method: 'POST',
        headers: { 'Content-Type': 'application/xml' },
        body: xmlData
      });
Content-Length

Content-Length:请求体大小(通常自动计算)

js
headers: {
  'Content-Length': '348'
}
Connection

Connection:用于控制网络连接行为,决定了客户端与服务器之间的 TCP 连接如何处理。

  • keep-alive最常用,要求服务器保持连接持续(HTTP/1.1 默认开启
  • close:明确要求请求后关闭连接
  • Upgrade:请求协议升级(如 HTTP → WebSocket)
  • TE:指定传输编码(如分块传输)
  • Trailers:声明将在分块消息后发送的尾部头字段

keep-alive 在 HTTP 不同版本中的差异

http是基于TCP协议的,但是通常在进行一次请求和响应结束后会立刻中断;

  1. HTTP1.0
    • 默认关闭连接
    • 需要显式声明 Connection: keep-alive
  • HTTP1.1

    • 默认启用持久连接
    • 空闲超时自动关闭(通常 5-15 秒)
  • HTTP2.0

    • 完全移除 Connection
    • 通过多路复用(Multiplexing)自动管理连接
    • 单个 TCP 连接处理所有请求
Keep-Alive

Keep-Alive:控制持久连接的细节。

  • timeout:空闲连接保持时间(秒)
  • max:连接关闭前最大请求数
js
// Connection 与 Keep-Alive 的配合使用
Connection: keep-alive
Keep-Alive: timeout=5, max=100
Accept

Accept:指定客户端可接受的 MIME 类型:

js
headers: {
  'Accept': 'application/json, text/plain, */*'
}
Accept-Encoding

Accept-Encoding:指定客户端支持的文件压缩格式。比如 js 文件可以使用 gzip 编码,对应 .gz 文件。

js
headers: {
  'Accept-Encoding': 'gzip, deflate, br'
}
User-Agent

User-Agent:标识客户端相关信息:

js
headers: {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'
}

// Chrome: 
// 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'

// Egdge:
// 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0'

HTTP 状态码

HTTP 状态码(HTTP Status Code):是服务器响应请求时返回的三位数字代码,用于表示请求的处理结果。


状态码分类体系

HTTP 状态码分为五类,通过首位数字标识:

分类范围含义JavaScript 处理重点
1xx100-199信息响应临时响应,前端通常自动处理
2xx200-299成功响应正常处理成功响应
3xx300-399重定向自动跟随或手动处理重定向
4xx400-499客户端错误处理用户端问题(如无效请求)
5xx500-599服务器错误处理服务端故障

常见状态码

状态码状态描述信息说明
200OK请求成功完成
201Created资源创建成功
204No Content请求成功但无返回内容
301Moved Permanently资源永久迁移
302Found资源临时移动
304Not Modified资源未修改(缓存有效)
400Bad Request请求语法错误
401Unauthorized未认证/缺少凭证
403Forbidden无权限访问
404Not Found资源不存在
429Too Many Requests请求过于频繁
500Internal Server Error通用服务器错误
502Bad Gateway上游服务器无效响应
503Service Unavailable服务暂时不可用

HTTP 响应头

HTTP 响应头(HTTP Response Headers):是服务器在响应客户端请求时发送的元数据信息,它们提供了关于响应内容的关键信息和控制指令。


常见 HTTP 响应头

image-20230620153030917

  1. 内容信息类

    1. Content-Type:声明响应体的 MIME 类型。常见值
      • text/html; charset=utf-8
      • application/json
      • image/png
    2. Content-Length:响应体的字节大小
  2. 缓存控制类

    1. Cache-Control:控制缓存行为。常用指令
      • max-age=3600:缓存有效期(秒)。用于静态资源缓存
      • no-cache:需重新验证。用于动态内容
      • no-store: 禁止缓存。用于 敏感数据
      • public:允许代理缓存。用于 CDN 资源
      • private:仅浏览器缓存。用于用户私有数据
    2. ETag / Last-Modified:资源验证标识
  3. 安全策略类

    1. Content-Security-Policy (CSP):防止 XSS 攻击。

      常见配置

      http
      Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.example.com
    2. Strict-Transport-Security (HSTS):强制 HTTPS 连接

      配置

      http
      Strict-Transport-Security: max-age=31536000; includeSubDomains
    3. X-Frame-Options:防止点击劫持。取值:

      • DENY:完全禁止嵌入
      • SAMEORIGIN:仅同源可嵌入
  4. CORS (跨域资源共享) 类

    1. Access-Control-Allow-Origin:允许跨域的源

      配置

      http
      Access-Control-Allow-Origin: https://yourdomain.com
      Access-Control-Allow-Origin: *  // 允许所有源
    2. Access-Control-Expose-Headers:允许前端访问的自定义头

    3. Access-Control-Allow-Headers:允许前端访问的响应头

  5. 性能优化类

    1. Content-Encoding:响应体压缩算法。常见值
      • gzip
      • br (Brotli)
      • deflate
    2. Connection:控制连接持久性

插件-FeHelper

为了之后查看数据更加的便捷、优雅,我们安装一个Chrome插件:

image-20230620153054393

AJAX

AJAX 概述

AJAX(Asynchronous JavaScript And XML):是一种用于创建异步 Web 应用的核心技术,它允许网页在不重新加载整个页面的情况下与服务器交换数据并更新部分内容


AJAX 定义与本质

  • AJAX 不是单一技术,而是多种技术的组合:
    • HTML/CSS:内容展示
    • DOM:动态内容操作
    • XMLHttpRequest:数据传输
    • JSON/XML:数据格式
  • 异步通信:在后台与服务器交换数据,不阻塞用户界面

核心特性

优点

  1. 用户体验提升无刷新更新内容
  2. 性能优化:减少带宽使用,只传输必要数据
  3. 异步处理不阻塞用户界面
  4. 模块化:前后端分离开发

缺点

  1. SEO 问题搜索引擎爬虫难以索引动态内容
  2. 浏览器历史:后退按钮行为需要额外处理
  3. 跨域限制:需要 CORS 或代理解决
  4. 调试复杂:异步流程增加调试难度

AJAX 核心实现方式

  1. 方式一:XMLHttpRequest (XHR)
  2. 方式二:Fetch

XHR

API-XHR

构造方法

  • new XMLHttpRequest()(),用于创建一个 XHR 实例对象。用于与服务器交互,支持异步 HTTP 请求(如 AJAX)。

属性

  • xhr.onreadystatechangefn事件处理,用于监听请求状态变化。会在 readyState 属性值变化时触发,是处理异步请求响应的传统方式。
  • xhr.readyState0|1|2|3|4只读,表示请求的当前状态
  • xhr.statusnumber只读,表示 HTTP 响应的状态码
  • xhr.statusTextstring只读,用于获取 HTTP 响应的状态文本
  • xhr.responseany只读,用于获取 HTTP 响应的内容主体。可以根据 responseType 设置自动解析响应内容。
  • xhr.responseTypestring默认:'text'可读写,用于指定服务器响应的数据类型,并控制如何解析响应数据。
  • xhr.timeoutnumber默认:0可读写,用于设置 HTTP 请求的超时时间(毫秒)。超时后请求自动终止并触发 timeout 事件。
  • xhr.withCredentialsboolean默认:false可读写,用于控制跨域请求是否携带用户凭证(如 cookies、HTTP 认证信息)。

方法

  • xhr.open()(method,url,async?,user?,password?),用于初始化 HTTP 请求配置(但不会发送请求)。需配合 send() 方法使用。
  • xhr.send()(body?),用于实际发送 HTTP 请求到服务器。必须在 open() 之后调用。
  • xhr.abort()(),用于立即终止正在进行的 HTTP 请求。调用后,请求会被取消,不会继续接收响应数据。
  • xhr.setRequestHeader()(header, value),用于在发送请求前设置 HTTP 请求头。确保在 open() 之后、send() 之前调用。
  • xhr.getResponseHeader()(headerName),用于获取指定 HTTP 响应头的值

事件

  • loadstart(event)=>void首个事件,在浏览器开始加载服务器响应时触发。
  • load(event)=>void核心成功事件,当请求成功完成且响应数据完全接收时触发。
  • loadend(event)=>void最终事件,在请求结束时触发(无论成功或失败)。用于清理资源执行最终操作
  • progress
  • abort
  • error
  • timeout

基本使用

new XMLHttpRequest()(),用于创建一个 XHR 实例对象。用于与服务器交互,支持异步 HTTP 请求(如 AJAX)。

xhr.open()(method,url,async?,user?,password?),用于初始化 HTTP 请求配置(但不会发送请求)。需配合 send() 方法使用。

xhr.send()(body?),用于实际发送 HTTP 请求到服务器。必须在 open() 之后调用。

xhr.onreadystatechangefn事件处理,用于监听请求状态变化。会在 readyState 属性值变化时触发,是处理异步请求响应的传统方式。


AJAX基本使用

  1. 第一步:创建网络请求的AJAX对象(使用XMLHttpRequest)

  2. 第二步:监听XMLHttpRequest对象状态的变化,或者监听onload事件(请求完成时触发);

  3. 第三步:配置网络请求(通过open方法);

  4. 第四步:发送send网络请求;

image-20250818180135429

XHR 请求状态 readyState

xhr.readyState0|1|2|3|4只读,表示请求的当前状态


readyState 状态详解

事实上,我们在一次网络请求中看到状态发生了很多次变化,这是因为对于一次请求来说包括如下的状态:

image-20230620153120678


XHR 执行流程

  1. 准备阶段
    • 调用 open() 初始化请求配置
    • readyState 变为 1 (OPENED)
    • 设置请求头(可选)
    • 注册事件处理器
  2. 发送阶段
    • send() 被调用
    • 请求进入发送队列
  3. 传输阶段
    • 服务器接收请求
    • readyState 变为 2 (HEADERS_RECEIVED)
    • readyState 变为 3 (LOADING) 数据接收中
  4. 完成阶段
    • readyState 变为 4 (DONE)
    • 触发 load/error/abort 事件

对比 status

  • readyState:记录的是 XMLHttpRequest 对象的状态变化,而非 HTTP 状态码。
  • status:记录的是 HTTP 状态码。

发送同步请求(已废弃)

open() 的第三个参数设置为 false

image-20230620153137354

XHR 事件

XHR 事件

除了onreadystatechange还有其他的事件可以监听:

  • loadstart(event)=>void首个事件,在浏览器开始加载服务器响应时触发。
  • load(event)=>void核心成功事件,当请求成功完成且响应数据完全接收时触发。
  • loadend(event)=>void最终事件,在请求结束时触发(无论成功或失败)。用于清理资源执行最终操作
  • progress
  • abort
  • error
  • timeout

XHR 请求生命周期

image-20250821103819316


示例:使用 load 监听获取数据

image-20250819160840156

响应数据和响应类型

响应数据

发送了请求后,我们可以通过 response 获取响应的正文内容。

xhr.responseany只读,用于获取 HTTP 响应的内容主体。可以根据 responseType 设置自动解析响应内容。


响应类型

response 返回的数据类型取决于 responseType 的属性设置。

xhr.responseTypestring默认:'text'可读写,用于指定服务器响应的数据类型,并控制如何解析响应数据。


示例:设置响应类型

image-20250819162851871


对比 responseText、responseXML

  • 早期:服务器返回的数据通常是普通的 textXML 类型:

    • 所以会通过 responseText responseXML 来获取响应结果。

    • 之后将它们转化成 JS 对象形式。

    js
    xhr.responseType = 'text'
    
    xhr.onload = function() {
      console.log(xhr.responseText)
      console.log(xhr.responseXML)
    }
  • 目前:服务器基本返回的数据都是 json 类型:

    • 直接设置为 json 即可
    js
    xhr.responseType = 'json'

HTTP 响应状态 status

XMLHttpRequest的 readyState 是用于记录 xhr 对象本身的状态变化,并非针对于 HTTP 的网络请求状态。

如果我们希望获取HTTP响应的网络状态,可以通过 statusstatusText 来获取。


xhr.statusnumber只读,表示 HTTP 响应的状态码

xhr.statusTextstring只读,用于获取 HTTP 响应的状态文本


示例

  1. 打印 HTTP 响应状态

    image-20250819164514309

  2. HTTP 响应状态检查

    js
    xhr.onreadystatechange = function() {
      if (this.readyState === 4) {
        // 主成功范围 (200-299)
        if (this.status >= 200 && this.status < 300) {
          console.log("请求成功");
        } else {
          console.error(`请求失败: ${this.status} ${this.statusText}`);
        }
      }
    };

参数传递方式@

在开发中,我们使用最多的是GET和POST请求,在发送请求的过程中,我们也可以传递数据给服务器。

参数传递的方式

常见的传递数据的方式有如下几种:

  • 方式1:GET 请求 query 参数

  • 方式2:POST 请求 x-www-form-urlencoded 格式

  • 方式3:POST 请求 FormData 格式

  • 方式4:POST 请求 JSON 格式


方式1:GET 请求 query 参数

  1. open() 中参数以 查询字符串(Query String)形式传递。
  2. GET 请求时 send() 参数为空。

image-20250819171252966


方式2:POST 请求 x-www-form-urlencoded 格式

  1. open() 中参数不携带查询字符串。

  2. 通过 setRequestHeader() 设置 Content-Type 请求头为 x-www-form-urlencoded

  3. send() 方法中携带 查询字符串 形式的参数。

image-20250819172937276


方式3:POST 请求 FormData 格式

  1. open() 中参数不携带查询字符串。
  2. 不要设置 Content-Type
  3. send() 方法中携带 FormData 实例对象

image-20250819174007077


方式4:POST 请求 JSON 格式

  1. open() 中参数不携带查询字符串。
  2. 通过 setRequestHeader() 设置 Content-Type 请求头为 applicaiton/json; chartset=utf-8
  3. send() 方法中携带 JSON.stringify(obj) 转化后的对象

image-20250819175012263

封装:AJAX 网络请求@

基本实现-GET(无参)

调用方法

image-20250819180507327

实现代码:GET 请求(无参)

image-20250819181115541

基本实现-GET(传参)

调用方法

  • 方式1:通过 url 传递参数

    image-20250820104635823

  • 方式2:通过 data 传递参数

    image-20250820104836051

代码实现:GET 请求(传参)

思路:拼接 data 为查询字符串,兼容通过 data 传递参数

image-20250820105919806

基本实现-POST

调用方法

image-20250820104427751

实现代码:POST 请求

思路:

  1. 设置 Content-Typeapplication/json
  2. send() 调用时传递 JSON.stringify(data) 转换后的参数

image-20250820110222296

优化:Promise

问题:回调地狱

回调地狱:第2次请求依赖第1次请求结果时会出现回调地狱的问题。

上述使用回调函数的实现方式在使用的时候会出现回调地狱的问题:

image-20250820111938898

解决:使用 Promise 的方式实现可以解决该问题。

调用方法

image-20250820112409472

实现代码:

  1. 使用 Promise 包裹之前的代码
  2. resolve() 成功的结果
  3. reject() 失败的结果

image-20250820112858715

优化:timeout

xhr.timeoutnumber默认:0可读写,用于设置 HTTP 请求的超时时间(毫秒)。超时后请求自动终止并触发 timeout 事件。


在网络请求的过程中,为了避免过长的时间服务器无法返回数据,通常我们会为请求设置一个超时时间:timeout

  • 当达到超时时间后依然没有获取到数据,那么这个请求会自动被取消掉;

  • 默认值为0,表示没有设置超时时间;

实现代码:

image-20250820114605126

优化:取消请求

xhr.abort()(),用于立即终止正在进行的 HTTP 请求。调用后,请求会被取消,不会继续接收响应数据。


我们可以通过 abort() 方法强制取消请求。

调用方法

image-20250820115515283

实现代码:

  • 回调形式思路:返回 xhr 对象实例,通过它调用 xhr.abort() 方法取消请求。

    image-20250820114824123

  • Promise形式思路

    通过为 promise 实例对象添加 xhr 属性,将 xhr 对象返回出去

    image-20250820115734804

优化:headers【

【TODO:自己实现】

image-20230620153331323

Fetch

API-Fetch

Fetch

方法

  • window.fetch()(url, options?),用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。

Response

属性

方法

Fetch 概述

Fetch API:是一个现代、强大且灵活的 JS 接口,用于在浏览器环境中发起异步网络请求(如 HTTP 请求)。它取代了陈旧的 XMLHttpRequest (XHR),提供了一个 基于 Promise 的、更简洁直观的方法来获取资源(无论是从一个 URL 获取数据,还是向服务器发送数据)。


Fetch 的优势 / 局限性

优势

  1. 基于 Promise: 语法清晰,避免了回调地狱。
  2. 语法简洁直观: 比 XMLHttpRequest 更容易使用。
  3. 内置 JSON 解析: 通过 .json() 方法轻松处理 JSON 数据。
  4. 符合现代标准: 是 W3C 规范,得到所有现代浏览器支持。
  5. 强大的配置能力: 通过 RequestHeaders 对象提供精细控制。

局限性

  1. 默认不携带 Cookie: 需要显式设置 credentials: 'include'
  2. HTTP 错误不会导致 Reject: 需要手动检查 response.ok
  3. 没有内置的超时 (timeout) 机制: 需要使用 AbortController 实现。
  4. 没有原生请求进度监控: 对于大文件上传/下载,监控进度比较麻烦(可通过 response.body 实现,但复杂)。
  5. 浏览器兼容性: 虽然现代浏览器都支持,但在非常旧的浏览器(如 IE)中完全不可用。

对比 XHR / Axios:

特性Fetch APIXMLHttpRequest (XHR)Axios
语法基于 Promise,简洁现代基于事件的回调,冗长复杂基于 Promise,简洁优雅
HTTP 错误处理不会 reject,需手动检查在事件回调中手动检查会自动 reject,更简单
JSON 转换需要调用 .json() 方法需要手动 JSON.parse()自动转换请求和响应数据
请求取消使用 AbortController使用 .abort() 方法使用 AbortController 或自定义 cancel token
请求/响应拦截无原生支持无原生支持有内置支持,非常强大
浏览器支持现代浏览器所有浏览器,包括 IE现代浏览器(通过 polyfill 可支持旧浏览器)
进度监控较难实现原生支持浏览器端原生支持,Node.js 端也可用

基本使用

window.fetch()(url, options?),用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。


基本语法

Fetch API 的核心是全局的 fetch() 函数。它接收一个必需的参数:资源的 URL。它返回一个 Promise 对象,这个 Promise 在请求完成后会解析为一个 Response 对象。

由于它基于 Promise,你可以优雅地使用 .then().catch() 进行链式调用,或者使用更现代的 async/await 语法。

js
fetch(url) // 发起一个默认的 GET 请求
  .then(response => {
    // 处理响应
  })
  .catch(error => {
    // 处理网络错误
  });

基本示例

  1. 使用 then

    js
    fetch('https://api.example.com/data')
      .then(response => {
        if (!response.ok) { // 如果状态码不是 2xx
          throw new Error(`HTTP 错误! 状态码: ${response.status}`);
        }
        return response.json(); // 返回解析 JSON 的 Promise
      })
      .then(data => {
        console.log(data); // 这里获取到最终的数据
      })
      .catch(error => {
        console.error('请求失败:', error);
      });
  2. 使用 async/await

    js
    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json(); // 解析 JSON 响应体
        console.log(data);
      } catch (error) {
        console.error('获取数据失败:', error);
      }
    }

请求配置

常见的请求配置

  • method:请求方法,如 'GET', 'POST', 'PUT', 'DELETE'
  • headers:一个对象,用于设置请求头(例如 {'Content-Type': 'application/json'})。
  • body:请求体数据。通常是 JSON 字符串、FormData、URLSearchParams 等。GET 和 HEAD 请求不能包含 body。
  • mode:请求的模式,如 'cors', 'no-cors', 'same-origin'
  • credentials:是否发送 cookies。如 'include'(总是发送)、'same-origin'(同源时发送)、'omit'(不发送)。

示例:设置请求配置发送 POST 请求

js
const userData = {
  name: 'John Doe',
  email: 'john@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json', // 告诉服务器我们发送的是 JSON
  },
  body: JSON.stringify(userData) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));

响应对象 Response

Fetch 数据响应阶段:Fetch 的数据响应主要分为两个阶段:

阶段1:服务器返回响应 response

fetch() 返回的 promise 就使用内置类 Response 来对响应头进行解析

  1. 检查 HTTP 状态码:通过检查响应头中的 HTTP 状态码以确定请求是否成功。

  2. reject 的情况

    • 无法建立 HTTP 请求,如网络问题或请求网址不存在。

    • 异常 HTTP 状态码,如 404 或 500,不会导致被 reject。

我们可以在 response 的属性中查看 HTTP 状态:


阶段2:获取 response 中的数据

我们需要使用一个其他的方法调用

发起请求

fetch() 的第二个参数是一个可选的 选项对象(options object),你可以用它来配置请求,包括设置请求方法(method)、请求头(headers)、请求体(body)等。

POST 发送 JSON

配置请求

  1. 设置 method:将请求方式设置为 POST
  2. 设置 headers:告诉服务器我们发送的是 JSON
  3. 设置 body:将 JS 对象转换为 JSON 字符串
js
const userData = {
  name: 'John Doe',
  email: 'john@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json', // 告诉服务器我们发送的是 JSON
  },
  body: JSON.stringify(userData) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));

POST 发送 FormData

配置请求:提交表单数据(表单中有文件上传)

  1. 设置 method:将请求方式设置为 POST
  2. 不要设置 headersContent-Type 会自动设置为 multipart/form-data,无需手动设置
  3. 设置 body创建 FormData 实例对象赋值给 body
js
const formData = new FormData();
formData.append('username', 'john_doe');
formData.append('avatar', fileInput.files[0]); // 假设有一个文件输入框

fetch('https://api.example.com/profile', {
  method: 'POST',
  body: formData // Content-Type 会自动设置为 multipart/form-data,无需手动设置
});

POST 发送 x-www-form-urlencoded

配置请求:提交表单数据

  1. 设置 method:将请求方式设置为 POST
  2. 设置 headers设置 Content-Type 为 application/x-www-form-urlencoded
  3. 设置 body将查询字符串赋值给 body
js
fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: 'name=tom&age=18'
})
.then(response => response.jons())
.then(data => console.log(data))

错误处理机制

Fetch 的错误处理需要特别注意:

  1. 只有当网络故障或请求无法完成时,Promise 才会被 reject(例如,网络断开、域名解析失败)。
  2. 对于 HTTP 错误状态(如 404 Not Found 或 500 Internal Server Error),Promise 不会被 reject。相反,response.ok 属性会变为 false

因此,你必须手动检查 response.okresponse.status 来抛出错误。

示例:完整的错误处理模式

js
fetch('https://api.example.com/not-found-page')
  .then(response => {
    if (!response.ok) { // 处理 HTTP 错误
      throw new Error(`服务器返回了 ${response.status} 错误`);
    }
    return response.json();
  })
  .then(data => {
    // 处理成功的数据
  })
  .catch(error => {
    // 这里会捕获两种错误:
    // 1. 由 throw 抛出的 HTTP 错误
    // 2. 网络本身导致的错误
    console.error('请求完全失败:', error);
  });

最佳实践

最佳实践

  1. 总是检查 response.ok: 不要假设请求一定会成功。

  2. 使用 async/await: 让异步代码看起来像同步代码,更易读。

  3. 处理网络错误和 HTTP 错误: 确保 .catch() 能捕获所有类型的失败。

  4. 设置正确的 Content-Type 请求头: 特别是发送 JSON 时,一定要设置 'Content-Type': 'application/json'

  5. 注意 CORS: 向不同域的服务器发起请求时,需要服务器正确配置 CORS 头,否则请求会被浏览器阻止。

  6. 实现请求超时: 使用 AbortController

    js
    // 1. 创建 AbortController 对象,并在5秒后调用它的 abort() 取消方法
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒后超时
    
    fetch(url, {
      // 2. 绑定 AbortController 对象到 fetch 的请求配置参数 signal 上
      signal: controller.signal
    }).then(...).catch(err => {
      // 3. 捕获取消请求后的的错误
      if (err.name === 'AbortError') {
        console.log('请求超时');
      }
    }).finally(() => {
      // 4. 始终清理创建的定时器
      clearTimeout(timeoutId);
    });

文件上传-前端

文件上传是开发中经常遇到的需求,比如头像上传、照片等。

要想真正理解文件上传,必须了解服务器如何处理上传的文件信息。

使用

image-20250820173320694

文件上传-XHR

代码实现

image-20250820173131502

文件上传-Fetch

Fetch 也支持文件上传,但是 Fetch 没办法监听进度

代码实现

image-20250820173839424